#include <bits/stdc++.h>
#define Extension 1
//!开启E拓展
#define Sbox 1
//!开启S盒代换
#define Pbox 0
//!开启P盒代换
using namespace std;
const int maxn(70);

void change1bit(bool R[32], int);
void output(bool *t, int l)
{
    for (int i = 1, d = 1; i <= l / 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            cout << t[d++];
        }
        cout << ' ';
    }
    cout << endl;
    cout << "--------------" << endl;
}
void ipTrans(bool m[maxn])
{
    bool cm[maxn];
    int s[] = {58, 60, 62, 64, 57, 59, 61, 63};
    for (int i = 0, l = 1; i < 8; i++)
    {
        for (int j = s[i]; j > 0; j -= 8)
        {
            cm[l++] = m[j];
        }
    }
    for (int i = 1; i <= 64; i++)
    {
        m[i] = cm[i];
    }
}
void PC_1(bool k[maxn])
{
    bool ck[maxn];
    int st[] = {57, 58, 59, 60, 63, 62, 61, 28};
    int le[] = {8, 8, 8, 4, 8, 8, 8, 4};
    for (int i = 0, l = 1; i < 7; i++)
    {
        for (int j = 0; j < le[i]; j++)
        {
            ck[l++] = k[st[i] - j * 8];
        }
    }
    for (int i = 0; i <= 56; i++)
    {
        k[i] = ck[i];
    }
}
int cirMv[] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
void circle_left(bool k[maxn], int t)
{
    t = cirMv[t];
    bool C[maxn >> 1], D[maxn >> 1];
    for (int i = 1; i <= 28; i++)
    {
        C[i] = k[i], D[i] = k[28 + i];
    }
    for (int j = 0; j < t; j++)
    {
        for (int i = 0; i < 28; i++)
        {
            C[i] = C[i + 1], D[i] = D[i + 1];
        }
        C[28] = C[0], D[28] = D[0];
    }
    for (int i = 1; i <= 28; i++)
    {
        k[i] = C[i], k[28 + i] = D[i];
    }
}
void PC_2(bool k[maxn], bool ck[maxn])
{
    int transTable[] = {
        14, 17, 11, 24, 1, 5,
        3, 28, 15, 6, 21, 10,
        23, 19, 12, 4, 26, 8,
        16, 7, 27, 20, 13, 2,
        41, 52, 31, 37, 47, 55,
        30, 40, 51, 45, 33, 48,
        44, 49, 39, 56, 34, 53,
        46, 42, 50, 36, 29, 32};
    for (int i = 0; i < 48; i++)
    {
        ck[i + 1] = k[transTable[i]];
    }
}
const int selectMatrix[8][4][16] = {
    // S1
    14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
    0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
    4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
    15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
    // S2
    15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
    3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
    0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
    13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
    // S3
    10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
    13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
    13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
    1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
    // S4
    7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
    13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
    10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
    3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
    // S5
    2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
    14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
    4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
    11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
    // S6
    12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
    10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
    9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
    4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
    // S7
    4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
    13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
    1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
    6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
    // S8
    13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
    1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
    7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
    2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11};
void encrypt_f(bool R[maxn], bool k[maxn], bool fR[maxn])
{
    bool ER[maxn], p[maxn], tmp[maxn];
    memset(ER, 10, maxn);
    int st[] = {0, 4, 8, 12, 16, 20, 24, 28};
    //***********E盒拓展***************
    if (Extension)
    {
        for (int i = 0, l = 1; i < 8; i++)
        {
            for (int j = 0; j < 6; j++)
            {
                ER[l++] = R[st[i] + j];
            }
        }
        ER[1] = R[32], ER[48] = R[1];
    }
    else
    {
        memset(ER, 0, maxn);
        memcpy(ER, R, 33);
    }

    for (int i = 1; i <= 48; i++)
    {
        ER[i] = ER[i] ^ k[i];
    }
    //***********S盒代换***************
    if (Sbox)
    {
        for (int i = 0, l = 1; i < 8; i++)
        {
            int locbit[10], row, column;
            for (int j = 1; j <= 6; j++)
            {
                locbit[j] = ER[i * 6 + j];
            }
            row = (locbit[1] << 1) | locbit[6];
            column = 0;
            for (int j = 2; j <= 5; j++)
            {
                column |= (int)locbit[j] << (5 - j);
            }
            int res = selectMatrix[i][row][column];
            for (int i = 3; i >= 0; i--)
            {
                p[l++] = (res & (1 << i)) ? 1 : 0;
            }
        }
    }
    else
    {
        for (int i = 0, l = 1; i < 8; i++)
        {
            for (int j = 2; j < 6; j++)
            {
                p[l++] = ER[i * 6 + j];
            }
        }
    }
    //***********P盒置换***************
    if (Pbox)
    {
        int p_trans[] = {
            16, 7, 20, 21,
            29, 12, 28, 17,
            1, 15, 23, 26,
            5, 18, 31, 10,
            2, 8, 24, 14,
            32, 27, 3, 9,
            19, 13, 30, 6,
            22, 11, 4, 25};
        for (int i = 0; i < 32; i++)
        {
            fR[i + 1] = p[p_trans[i]];
        }
    }
    else
    {
        for (int i = 1; i < 33; i++)
        {
            fR[i] = p[i];
        }
    }
}
void re_ipTrans(bool m[maxn])
{
    bool cm[maxn];
    int st[] = {40, 8, 48, 16, 56, 24, 64, 32};
    for (int i = 0, l = 1; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            cm[l++] = m[st[j] - i];
        }
    }
    for (int i = 1; i <= 64; i++)
    {
        m[i] = cm[i];
    }
}
int main()
{
    bool m[maxn], k[maxn], ck[maxn];
    bool m0[maxn], k0[maxn], ck0[maxn];
    bool tmpL[6][maxn], tmpR[6][maxn];
    bool tmpC[maxn];
    memset(tmpL, 0, maxn * 6);
    memset(tmpR, 0, maxn * 6);
    memset(tmpC, 0, maxn);
    int n = 64;
    int changeflag = 0;
    char in[6];
    int changeindex;
    char OfileName[16];
    char mode[4];
    memset(mode,0,4);
    mode[0] = Extension + '0';
    mode[1] = Sbox + '0';
    mode[2] = Pbox + '0';


    strcpy(OfileName, "data_out");
    strcat(OfileName, mode);
    strcat(OfileName, ".txt");

    cout << "输入打算更改的比特位1~32(第几比特)" << endl;
    cin >> changeindex;
    freopen(OfileName, "w", stdout);
    freopen("data_in.txt", "r", stdin);
    for (int i = 0, l = 1; i < 16; i++)
    {
        cin >> in;
        for (int j = 0; j < 4; j++)
        {
            m[l] = in[j] - '0';
            m0[l++] = in[j] - '0';
        }
    }
    for (int i = 0, l = 1; i < 16; i++)
    {
        cin >> in;
        for (int j = 0; j < 4; j++)
        {
            k[l] = in[j] - '0';
            k0[l++] = in[j] - '0';
        }
    }
    cout << "E拓展\t" << Extension << endl;
    cout << "S盒代换\t" << Sbox << endl;
    cout << "P盒置换\t" << Pbox << endl;

    while (changeflag < 2)
    {
        cout << "----------------------------------------------------------------------" << endl;
        cout << "更改\t" << changeflag << endl;

        if (changeflag)
        {
            memcpy(m, m0, sizeof(bool) * maxn);
            memcpy(k, k0, sizeof(bool) * maxn);
            memcpy(ck, ck0, sizeof(bool) * maxn);
        }

        // 初始置换IP
        ipTrans(m);
        bool L[maxn >> 1], R[maxn >> 1], cR[maxn >> 1];
        memset(cR, 0, maxn >> 1);
        for (int i = 1; i <= 32; i++)
        {
            L[i] = m[i], R[i] = m[32 + i];
        }
        PC_1(k);
        for (int i = 0; i < 16; i++)
        {
            if (i == 0)
            {
                int o;
                o++;
            }
            // 子密钥生成
            circle_left(k, i);

            PC_2(k, ck);
            // 加密函数f
            encrypt_f(R, ck, cR);
            //获得新的L和R

            for (int j = 1; j <= 32; j++)
            {
                cR[j] ^= L[j];
            }
            for (int j = 1; j <= 32; j++)
            {
                L[j] = R[j];
                R[j] = cR[j];
            }
            if (i == 0)
            {
                cout << "第" << i << "轮" << endl;
                cout << "L = ";
                output(L, 32);
                cout << "R = ";
                output(R, 32);
                if (changeflag)
                {
                    change1bit(R, changeindex);
                }
            }
            if (0 < i && i <= 6)
            {
                cout << "第" << i << "轮" << endl;
                cout << "L = ";
                output(L, 32);
                if (changeflag)
                {
                    cout << "L原 = ";
                    output(tmpL[i], 32);
                }
                cout << "R = ";
                output(R, 32);
                if (changeflag)
                {
                    cout << "R原 = ";
                    output(tmpR[i], 32);
                }

                if (!changeflag)
                {
                    for (int cp = 0; cp <= 32; cp++)
                    {
                        tmpL[i][cp] = L[cp];
                        tmpR[i][cp] = R[cp];
                    }
                }
                else
                {
                    int times = 0;
                    cout << "相比较输出 L :" << endl;

                    for (int cmp = 0; cmp <= 32; cmp++)
                    {
                        if (tmpL[i][cmp] ^ L[cmp])
                        {
                            cout << cmp << " ";
                            times++;
                        }
                    }
                    cout << "共" << times << "个" << endl;
                    times = 0;
                    cout << "相比较输出 R :" << endl;
                    for (int cmp = 0; cmp <= 32; cmp++)
                    {
                        if (tmpR[i][cmp] ^ R[cmp])
                        {
                            cout << cmp << " ";
                            times++;
                        }
                    }
                    cout << "共" << times << "个" << endl;
                    times = 0;
                    cout << "-----------------" << endl;
                }
            }
        }
        for (int i = 1; i <= n / 2; i++)
        {
            m[i] = R[i], m[i + 32] = L[i];
        }
        re_ipTrans(m);

        cout << "\n--------------\n最终密文:" << endl;
        output(m, 64);
        if (!changeflag)
        {
            for (int cp = 0; cp <= 64; cp++)
            {
                tmpC[cp] = m[cp];
            }
        }
        else
        {
            int times = 0;
            cout << "原最终密文:" << endl;
            output(tmpC, 64);
            cout << "相比较输出 :" << endl;

            for (int cmp = 0; cmp <= 64; cmp++)
            {
                if (tmpC[cmp] ^ m[cmp])
                {
                    cout << cmp << " ";
                    times++;
                }
            }
            cout << "共" << times << "个" << endl;
        }
        changeflag++;
    }

    return 0;
}

void change1bit(bool R[32], int index)
{
    R[index] = !R[index];
    return;
}